﻿/* 
 Copyright (C) 2011  Amblox Project

  This program is free software: you can redistribute it and/or modify
  it under the terms of the GNU General Public License as published by
  the Free Software Foundation, either version 3 of the License, or
  (at your option) any later version.

  This program is distributed in the hope that it will be useful,
  but WITHOUT ANY WARRANTY; without even the implied warranty of
  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
  GNU General Public License for more details.

  You should have received a copy of the GNU General Public License
  along with this program.  If not, see <http://www.gnu.org/licenses/>.
*/

using System;
using System.Collections.Generic;
using System.Net;
using System.Net.Sockets;
using System.Threading;

namespace Amblox.Net
{
    public static class NetListener
    {
        static Socket Listener;
        static Dictionary<int, NetConnection> Connections;
        static Thread PingSystem;

        public static void Init(int Port)
        {
            try
            {
                Connections = new Dictionary<int, NetConnection>();
                IPAddress ipAdd = IPAddress.Any;
                EndPoint ep = new IPEndPoint(ipAdd, Port);

                Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);
                Listener.Bind(ep);
                Listener.Listen(10);
                Listener.BeginAccept(new AsyncCallback(OnReceive), null);

                PingSystem = new Thread(new ThreadStart(PingConnections));
                PingSystem.Priority = ThreadPriority.BelowNormal;
                PingSystem.Start();
            }
            catch (Exception e)
            {
                Log.WriteError("Unhandled error on initializing listener socket: " + e.Message);
            }
        }

        public static NetConnection GetNetConnection(Socket Con)
        {
            int ID = GetNewID();
            NetConnection Conn = new NetConnection(ID, Con);
            Connections.Add(ID, Conn);
            return Conn;
        }

        public static void OnReceive(IAsyncResult IAs)
        {
            try
            {
                NetConnection Connection = GetNetConnection(Listener.EndAccept(IAs));

            }
            catch (Exception e)
            {
                Log.WriteError("Unhandled error on accepting socket request: " + e.Message);
            }

            Listener.BeginAccept(new AsyncCallback(OnReceive), null);
        }

        public static void RemoveConnection(int ID)
        {
            if (Connections.ContainsKey(ID))
                Connections.Remove(ID);
        }

        public static int GetNewID()
        {
            int i;
            for (i = 0; Connections.ContainsKey(i); i++) { }
            return i;
        }

        public static void PingConnections()
        {
            while (true)
            {
                List<NetConnection> Pinged = new List<NetConnection>();

                foreach (NetConnection Con in Connections.Values)
                {
                    Con.Ping();
                    Pinged.Add(Con);
                }

                Thread.Sleep(Convert.ToInt32(Environment.Config["Ping.Timeout"]));

                foreach (NetConnection Con in Pinged)
                {
                    if (Con.PongStatus)
                        continue;

                    Con.Destroy();
                }

                int Sleeptime = Convert.ToInt32(Environment.Config["Ping.Sleeptime"]);
                
                if(Sleeptime > 0)
                    Thread.Sleep(Sleeptime);
            }
        }
    }
}
